<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="keywords" content="promise，手写，头条">
  <title>Document</title>
</head>

<body>
  <div id="id">123124</div>
  <script>
    let div = document.getElementById("id");
    function csl() {
      console.log(1)
    }
    div.addEventListener("click", fangdou(csl, 2000))
    // 防抖
    function fangdou(fn, t) {
      let time
      return function () {
        clearTimeout(time)
        time = setTimeout(() => {
          fn()
        }, t);
      }
    }

    // 节流
    function jieliu(fn, time) {
      let timer = 0
      return function () {
        if (new Date() - timer >= time) {
          fn()
          timer = new Date()
        }
      }
    }

    // deepclone
    function deepClone(target) {
      if (typeof target !== "object") {
        return target
      }
      if (target == null) {
        return null
      }

      let newobj = new target.constructor
      for (let i in target) {
        newobj[i] = deepClone(target[i])
      }
      return newobj
    }

    // call apply
    Function.prototype.MyCall = function () {
      let newthis = arguments[0]
      let args = [...arguments].slice(1)
      let fn = this
      let isStrick = (function () { return this == undefined })()
      if (!isStrick) {
        if (typeof newthis == "number") {
          newthis = new Number(newthis)
        } else if (typeof newthis == "string") {
          newthis = new String(newthis)
        }// ...
      }
      if (newthis == null) {
        return fn(...args)
      }
      let sym = Symbol(fn)
      newthis[sym] = fn
      return newthis[sym](...args)
    }

    // bind 
    Function.prototype.MyBind = function () {
      let fn = this;
      let target = arguments[0]
      let rest = [...arguments].slice(1)
      function realBind() {
        let args = [...rest, ...arguments]
        return fn.apply(this instanceof realBind ? this : target, args)
      }
      realBind.prototype = Object.create(fn.prototype || Function.prototype)
      return realBind
    }

    function flatArr(arr) {
      if (!Array.isArray(arr)) {
        return arr
      }

      let newarr = []
      for (let i in arr) {
        if (Array.isArray(arr[i])) {
          newarr = newarr.concat(flatArr(arr[i]))
        } else {
          newarr.push(arr[i])
        }
      }
      return newarr
    }
    // console.log(flatArr([1,2,3,[4,5,[6,7,[8]]]]))
    // console.log([1,2,3,[4,5,[6,7,[8]]]].toString().split(",").map(item => item -0 ))

    // 去重
    let repeatarr = [1, 2, 3, 1, 2, 3, 3, 4]
    console.log([...new Set(repeatarr)])
    // 快慢指针 indexOf  lastindexOf

    // let func1 = () => console.log("func1")
    // func1 = func1.bofore(()=>{console.log("===before===")}).after(()=>{console.log("===after===")})
    // let func2 = () => console.log("func2")
    // func2 = func2.bofore(()=>{console.log("===before===")}).after(()=>{console.log("===after===")})
    /*
      输出 
      ===before===
      func1
      ===after===
      ===before===
      func2
      ===after===      
    */


    // foreach 的异步问题
    // 实现 9s输出 1后 8s输出2 以此类推,有大佬知道为什么第一种方式await卡不住吗，9秒后会直接输出 1 2 3 4
    // var arr = [1, 2, 3, 4];
    //   (async () => {
    //     // 方法1
    //     arr.forEach(async element => {
    //       let rsesult = await new Promise(res => setTimeout(() => {
    //         console.log(element * 1000)          
    //         res(element)            
    //       }, 10000 - element * 1000))
    //       console.log(rsesult)
    //     });
    //     // 方法2
    //     // for (let i = 0; i < arr.length; i++) {
    //     //   let rsesult = await new Promise(res => setTimeout(() => {
    //     //     res(arr[i])
    //     //   }, 10000 - arr[i] * 1000))
    //     //   console.log(rsesult)
    //     // }
    //   })()

    // 函数柯里化
    function kelihua() {
      let fn = arguments[0]
      let rest = [...arguments].slice(1)

      function realK() {
        let param = [...rest, ...arguments]
        return kelihua(fn, ...param)
      }
      realK.toString = function () {
        return fn(...rest)
      }

      return realK
    }

    function add() {
      let sum = [...arguments].reduce((pre, cur) => {
        return pre + cur
      })
      return sum
    }

    // console.log(kelihua(add,1,2,3)(4,5)(6).toString())

    // 手写new
    function myNew(target, ...args) {
      // 创建一个新对象
      let obj = {}
      obj.__proto__ = target.prototype
      target.apply(obj, args)
      return obj
    }

    // 事件委托
    function delegate(father, event, target, func) {
      father.addEventListener(event, function (e) {
        let event = e || window.event
        let el = e.target
        while (1) {
          if (el.tagName.toLowerCase() = target.toLowerCase()) {
            func(e)
            break;
          }
          if (el.tagName.toLowerCase() !== father.tagName.toLowerCase()) {
            break;
          }
          el = el.parentNode
        }
      })
    }

    // instanceof 手写
    function myInstanceOf(left, right) {
      if (typeof left !== "object")
        return false
      if (left == null)
        return false
      left = left.__proto__
      right = right.prototype
      while (left) {
        if (left == right)
          return true
        left = left.__proto__
      }
      return false
    }

    // 类数组转数组
    function changeTobeArr() {
      console.log([...arguments])
      console.log(Array.from(arguments))
    }

    // 迭代
    let obj = {
      a: 1,
      b: 2,
      c: 3,
      [Symbol.iterator]: function () {
        let that = this
        let keys = Object.keys(that)
        let i = -1
        return {
          next() {
            i++
            return {
              value: that[keys[i]],
              done: i == keys.length,
            }
          }
        }
      }
    }
    // console.log([...obj])
    // console.log([...obj].splice(0, 2))

    // 数组方法手写
    Array.prototype.myReduce = function () {
      let arr = this
      let i = arguments[1] ? 0 : 1
      let sum = i ? arr[0] : arguments[1]
      for (i; i < arr.length; i++) {
        sum = arguments[0](sum, arr[i])
      }
      return sum
    }
    // var arrx = [1,2,3,4]
    // console.log(arrx.myReduce((pre,cur) => pre+cur , 5))

    // async
    function myasync(genaration) {
      return function () {
        let gen = genaration.apply(this, arguments)
        return new Promise((resolve, reject) => {
          function step(key, value) {
            let result
            try {
              result = gen[key](value)
            } catch (err) {
              return reject(err)
            }

            let { val, done } = gen
            if (done) {
              return resolve(done)
            } else {
              return Promise.resolve(val).then(
                res => step('next', res),
                err => step('throw', err)
              )
            }
          }
          step('next')
        })
      }
    }

    // 消息发布订阅
    let event = {
      list: [],
      on(name, fn) {
        if (!this.list[name]) {
          this.list[name] = []
        }
        this.list.name.push(fn)
      },
      emit(name, ...args) {
        if (!this.list[name])
          return
        this.list[name].forEach(item => { item(args) })
      },
      off(name, fn) {
        if (!this.list[name])
          return
        if (!fn) {
          this.list[name] = []
        } else {
          for (let i = 0; i < this.list[name].length; i++) {
            if (this.list[name][i] == fn) {
              this.list[name].splice(i, 1)
              break;
            }
          }
        }
      }
    }

    // 模拟 setInterval
    function setinter(fn, time) {
      try {
        fn()
      } catch (err) {
        return console.log(err)
      }
      setTimeout(() => {
        setinter(fn, time)
      }, time);
    }

    // 浮点数误差去除
    function clearDecimal(left, right) {
      return Math.abs(left - right) < Number.EPSILON
    }

    // Object.is 问题解决 +0 -0 NaN
    function battle(left, right) {
      if (left == right) {
        return left !== 0 && right !== 0 && left / 1 == right / 1
      } else {
        return left !== left && right !== right
      }
    }

    // 洋葱模型
    function f(next) {
      console.log(1)
      next()
      console.log(2)
    }

    function h(next) {
      console.log(3)
      next()
      console.log(4)
    }

    function g(next) {
      console.log(5)
      next()
      console.log(6)
    }

    const fn = compose(f, h, g)
    fn() // 1,3,5,6,4,2

    function compose(...funcs) {
      return function () {
        const exec = (index) => {
          const fn = funcs[index]
          if (!fn) return
          fn(function () {
            exec(index + 1)
          })
        }
        exec(0)
      }
    }

  </script>
</body>

</html>